#include "Includes.h"
#include "stdio.h"
#include "DRV_Rtc.h"

_calendar_obj calendar;

//月份数据表
u8 const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; //月修正数据表

//平年的月份日期表
const u8 mon_table[12]  = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};


/*******************************************************************************
* Function Name  : 
* Description    : 
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RTC_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
    PWR_BackupAccessCmd(ENABLE);
    
	//识别是不是后背备份区域
    if(BKP_ReadBackupRegister(BKP_DR1)!=0xA1A1)
    {
        printf("RTC first time init\r\n");
        
        //RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_BKP , ENABLE);  /* 使能RTC和BKP时钟 */
        //PWR_BackupAccessCmd(ENABLE);                                                /* 使能RTC和后备寄存器访问 */
        BKP_DeInit();                                                               /* 将外设BKP的全部寄存器重设为缺省值 */
        RCC_LSEConfig(RCC_LSE_ON);                                                  /* 开启LSE */
        while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);                           /* 等待LSE起振 */
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                                     /* 选择LSE为RTC时钟源 */
        RCC_RTCCLKCmd(ENABLE);                                                      /* 使能RTC时钟 */
        RTC_WaitForSynchro();                                                       /* 等待RTC寄存器与RTC的APB时钟同步完成 */
        RTC_WaitForLastTask();                                                      /* 等待最近一次对RTC寄存器的写操作完成 */
        //RTC_ITConfig(RTC_IT_SEC,ENABLE);                                            /* 使能RTC秒中断 */
        //RTC_WaitForLastTask();                                                      /* 等待最近一次对RTC寄存器的写操作完成 */
        RTC_SetPrescaler(32767);                                                    /* 设置RTC时钟分频值为32767 */
        RTC_WaitForLastTask();                                                      /* 等待最近一次对RTC寄存器的写操作完成 */
        RTC_Set(2024,1,6,11,7,0);                                                   /* 设置默认时间 */
        BKP_WriteBackupRegister(BKP_DR1, 0xA1A1);                                   /* 配置完成后，向BKP数据寄存器2中写特殊字符0xA587 */
	}else
    {
		//看是否是系统掉电
		if(RCC_GetFlagStatus(RCC_FLAG_PORRST)!=RESET){
            printf("Power On Resetm occurred...\r\n");
		}
		//看是否是复位引脚引起的复位
		else if(RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET){
            printf("External Reset occured...\r\n");
		}
		printf("No need to configure RTC...\r\n");
        RTC_WaitForSynchro();
		RTC_ITConfig(RTC_IT_SEC,ENABLE);
		RTC_WaitForLastTask();
	}
    RCC_ClearFlag();
    
    RTC_Get(&calendar);
}


//判断是否是闰年函数
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 IS_Leap_Year( u16 year )
{
    //能被4或者400整除，并且不能被100整除
    if( ( ( year % 4 == 0 ) || ( year % 400 == 0 ) ) && ( year % 100 != 0 ) )
        return 1;
    else
        return 0;

}


//设置时钟
//把输入的时钟转换为秒钟
//以1970年1月1日为基准
//1970~2099年为合法年份
//返回值:0,成功;其他:错误代码.
u8 RTC_Set( u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec )
{
    u16 t;
    u32 seccount = 0;
    if( syear < 1970 || syear > 2099 )
        return 1;
    for( t = 1970; t < syear; t++ )						//所有年份的秒钟相加
    {
        if( IS_Leap_Year( t ) )
            seccount += 31622400;						//闰年秒钟数
        else
            seccount += 31536000;						//平年秒钟数
    }
    smon -= 1;
    for( t = 0; t < smon; t++ )							//把前面月份的秒钟数相加
    {
        seccount += ( u32 )mon_table[t] * 86400;
        if( IS_Leap_Year( syear ) && t == 1 )		    //闰年2月份增加一天的秒钟数
            seccount += 86400;
    }
    seccount += ( u32 )( sday - 1 ) * 86400;		    //把前面天数的秒钟数相加
    seccount += ( u32 )hour * 3600;						//加小时秒钟数
    seccount += ( u32 )min * 60;					    //加分钟秒钟数
    seccount += sec;									//加上最后的秒数

    RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE );
    PWR_BackupAccessCmd( ENABLE );

    RTC_SetCounter( seccount );							//设置RTC计数器的值
    RTC_WaitForLastTask();
    return 0;
}

//初始化闹钟
//以1970年1月1日为基准
//1970~2099年为合法年份
//syear,smon,sday,hour,min,sec：闹钟的年月日时分秒
//返回值:0,成功;其他:错误代码.
u8 RTC_Alarm_Set( u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec )
{
    u16 t;
    u32 seccount = 0;
    if( syear < 1970 || syear > 2099 )
        return 1;
    for( t = 1970; t < syear; t++ )						//所有年份的秒钟相加
    {
        if( IS_Leap_Year( t ) )
            seccount += 31622400;						//闰年秒钟数
        else
            seccount += 31536000;						//平年秒钟数
    }
    smon -= 1;
    for( t = 0; t < smon; t++ )							//把前面月份的秒钟数相加
    {
        seccount += ( u32 )mon_table[t] * 86400;
        if( IS_Leap_Year( syear ) && t == 1 )		    //闰年2月份增加一天的秒钟数
            seccount += 86400;
    }
    seccount += ( u32 )( sday - 1 ) * 86400;		    //把前面天数的秒钟数相加
    seccount += ( u32 )hour * 3600;						//加小时秒钟数
    seccount += ( u32 )min * 60;							//加分钟秒钟数
    seccount += sec;									//加上最后的秒数

    RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE );
    PWR_BackupAccessCmd( ENABLE );

    RTC_SetAlarm( seccount );
    RTC_WaitForLastTask();

    return 0;
}

//获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//输入参数：公历年月日
//返回值：星期号
u8 RTC_Get_Week( u16 year, u8 month, u8 day )
{
    u16 tem;
    u8 yearH, yearL;
    yearH = year / 100;
    yearL = year % 100;
    if( yearH > 19 )
        yearL += 100;
    tem = yearL + yearL / 4;
    tem = tem % 7;
    tem = tem + day + table_week[month - 1];
    if( yearL % 4 == 0 && month < 3 )
        tem--;
    return tem % 7;
}


//得到当前的时间
//返回值:0,成功;其他:错误代码.
u8 RTC_Get(_calendar_obj *pcalendar)
{
    static u16 daycnt = 0;
    u32 timecount = 0;
    u32 temp = 0;
    u16 temp1 = 0;
    timecount = RTC_GetCounter();
    temp = timecount / 86400;							//得到天数 小于1天时，秒小于86400

    if( daycnt != temp )
    {
        daycnt = temp;
        temp1 = 1970;
        while( temp > 365 )								//超过1年
        {
            if( IS_Leap_Year( temp1 ) )			        //闰年
            {
                if( temp > 366 )
                {
                    temp -= 366;
                }
                else
                {
                    temp1++;
                    break;
                }
            }
            else										//平年
            {
                temp -= 365;
            }
            temp1++;
        }
        calendar.w_year = temp1;						//得到年份
        temp1 = 0;
        while( temp >= 28 )								//超过1月
        {
            if( IS_Leap_Year( calendar.w_year ) && temp1 == 1 )
            {
                if( temp >= 29 )
                    temp -= 29;
                else
                    break;
            }
            else
            {
                if( temp >= mon_table[temp1] )
                    temp -= mon_table[temp1];
                else
                    break;
            }
            temp1++;
        }
        pcalendar->w_month = temp1 + 1;					//月
        pcalendar->w_date = temp + 1;				    //日
    }
    temp = timecount % 86400;
    pcalendar->hour = temp / 3600;
    pcalendar->min = ( temp % 3600 ) / 60;
    pcalendar->sec = ( temp % 3600 ) % 60;
    pcalendar->week = RTC_Get_Week( calendar.w_year, calendar.w_month, calendar.w_date );
    return 0;
}

